﻿
using System.Diagnostics.Contracts;

namespace Microsoft.Windows.Shell {
   using System;
   using System.Windows;
   using System.Windows.Input;
   using System.Windows.Interop;
   using Standard;

   public static class SystemCommands {
      public static RoutedCommand CloseWindowCommand { get; private set; }
      public static RoutedCommand MaximizeWindowCommand { get; private set; }
      public static RoutedCommand MinimizeWindowCommand { get; private set; }
      public static RoutedCommand RestoreWindowCommand { get; private set; }
      public static RoutedCommand ShowSystemMenuCommand { get; private set; }
      public static RoutedCommand ToggleTopmostCommand { get; private set; }

      static SystemCommands() {
         CloseWindowCommand = new RoutedCommand("CloseWindow", typeof(SystemCommands));
         MaximizeWindowCommand = new RoutedCommand("MaximizeWindow", typeof(SystemCommands));
         MinimizeWindowCommand = new RoutedCommand("MinimizeWindow", typeof(SystemCommands));
         RestoreWindowCommand = new RoutedCommand("RestoreWindow", typeof(SystemCommands));
         ShowSystemMenuCommand = new RoutedCommand("ShowSystemMenu", typeof(SystemCommands));
         ToggleTopmostCommand = new RoutedCommand("ToggleTopmost", typeof(SystemCommands));
      }

      private static void _PostSystemCommand(Window window, SC command) {
         IntPtr hwnd = new WindowInteropHelper(window).Handle;
         if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) {
            return;
         }

         NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr((int)command), IntPtr.Zero);
      }


      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")]
      public static void ToggleTopmost(Window window) {
         Contract.Requires(window != null, "window must not be null");
         Verify.IsNotNull(window, "window");
         window.Topmost = !window.Topmost;
      }

      public static void CloseWindow(Window window) {
         Verify.IsNotNull(window, "window");
         _PostSystemCommand(window, SC.CLOSE);
      }

      public static void MaximizeWindow(Window window) {
         Verify.IsNotNull(window, "window");
         _PostSystemCommand(window, SC.MAXIMIZE);
      }

      public static void MinimizeWindow(Window window) {
         Verify.IsNotNull(window, "window");
         _PostSystemCommand(window, SC.MINIMIZE);
      }

      public static void RestoreWindow(Window window) {
         Verify.IsNotNull(window, "window");
         _PostSystemCommand(window, SC.RESTORE);
      }

      /// <summary>Display the system menu at a specified location.</summary>
      /// <param name="screenLocation">The location to display the system menu, in logical screen coordinates.</param>
      public static void ShowSystemMenu(Window window, Point screenLocation) {
         Verify.IsNotNull(window, "window");
         ShowSystemMenuPhysicalCoordinates(window, DpiHelper.LogicalPixelsToDevice(screenLocation));
      }

      internal static void ShowSystemMenuPhysicalCoordinates(Window window, Point physicalScreenLocation) {
         const uint TPM_RETURNCMD = 0x0100;
         const uint TPM_LEFTBUTTON = 0x0;

         Verify.IsNotNull(window, "window");
         IntPtr hwnd = new WindowInteropHelper(window).Handle;
         if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) {
            return;
         }

         IntPtr hmenu = NativeMethods.GetSystemMenu(hwnd, false);

         uint cmd = NativeMethods.TrackPopupMenuEx(hmenu, TPM_LEFTBUTTON | TPM_RETURNCMD, (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero);
         if (0 != cmd) {
            NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero);
         }
      }
   }
}
